home *** CD-ROM | disk | FTP | other *** search
/ Language/OS - Multiplatform Resource Library / LANGUAGE OS.iso / oper_sys / presto / prest1_0.lha / src / hc_slock_asm.h < prev    next >
C/C++ Source or Header  |  1991-12-11  |  9KB  |  285 lines

  1. #ifndef __presto__hc_slock_asm_h__
  2. #define __presto__hc_slock_asm_h__
  3.  
  4. /*
  5.  *  hc_slock_asm.h
  6.  *
  7.  *  Queue-based spinlock specialized for situations where there is high
  8.  *  contention for the lock.
  9.  *
  10.  *  In a regular spinlock, all threads requesting the lock spin, performing
  11.  *  test-and-set operations on a single shared memory location.  The
  12.  *  resulting cache invalidation traffic quickly saturates the bus with
  13.  *  only a small number of spinning processors, impacting the performance
  14.  *  of the thread holding the lock (by interfering with it's ability to
  15.  *  access memory) and causing a rapid falloff in performance.
  16.  *
  17.  *  The queue-based spinlock is designed to eliminate this problem.  Threads
  18.  *  spin on a private location instead of a shared location, eliminating the
  19.  *  cache invalidation traffic.  To release a lock, the thread holding the
  20.  *  lock simply sets the private location that the next waiter is spinning on
  21.  *  (in this case no atomic instruction is needed).
  22.  *
  23.  *  Since C++ doesn't know about asm functions yet, this file gets pulled into
  24.  *  C++'s straight C output via the +hasmdefs.h C++ flag.
  25.  *
  26.  *  Depends on:
  27.  *
  28.  *  declaration of hc_slock_t in parallel.h
  29.  *  declaration of HC_Spinlock class in spinlock.h
  30.  *
  31.  *  Modification History:
  32.  *
  33.  *  28-Dec-1989  JEF
  34.  *  Integrated HC_Spinlock asm functions (after original version by raj).
  35.  *
  36.  */
  37.  
  38. /* 
  39.  * XXX Warning:
  40.  *    this will have to be changed if the structure of "thisproc"
  41.  *    changes.  for now, we "know" that the "p_pid" field is at
  42.  *    offset 24.
  43.  */
  44. #ifndef THISPROC_ID_OFFSET
  45. #define THISPROC_ID_OFFSET 24
  46. #endif /* THISPROC_ID_OFFSET */
  47.  
  48. #if defined(ATT_CFRONT_2_1) && !defined(__STDC__)
  49. #define void char
  50. #endif
  51.  
  52. /*
  53.  *  HC_S_LOCK - acquire high contention spinlock.
  54.  */
  55. asm void HC_S_LOCK(laddr)
  56. {
  57. %reg laddr; lab spin, done;
  58. /PEEPOFF
  59.     /* 
  60.          * Get process id for processor on which this thread is
  61.          * running.  Convert from 0 to NUMPROCS-1 form to 1 to NUMPROCS,
  62.          * since the lock data structure uses row 0 for something special.
  63.      */
  64.     movl    _thisproc, %edx
  65.     movl    THISPROC_ID_OFFSET(%edx), %edx
  66.     incl    %edx
  67.  
  68.     /*
  69.          * We use the calulated process id (in range 1 to NUMPROCS) to index
  70.          * into the lock data structure to find our private data location (the
  71.          * location on which a thread that requests a lock after us will
  72.          * spin).
  73.          * 
  74.          * The complex addressing mode of the 'movb' below only accepts
  75.          * a byte offset of 8 (max) -- since our private location is at
  76.          * an offset of 16, double our process id.
  77.      */
  78.     addl    %edx, %edx
  79.     movl    %edx, %eax
  80.  
  81.     /*
  82.          * Load contents of this processor's private data location into
  83.          * high bits of %eax.
  84.          *
  85.          *   %ah = 16 (laddr + (2*p_pid)*8)
  86.          *       = 16 (laddr + 16*p_pid)
  87.          *       = laddr [p_pid] [16]
  88.      */
  89.     movb    16(laddr,%edx,8),%ah
  90.  
  91.     /*
  92.          * Atomically exchange entire contents of %eax with contents of
  93.          * first longword in row 0 of laddr.  Row 0 always contains info
  94.          * identifying last process to request lock.
  95.          *
  96.          * Before:
  97.          *   %ah = laddr [p_pid] [16]  (orig contents of my private data area)
  98.          *   %al = p_pid*2             (next lock requestor uses this to
  99.          *                              find CURRENT contents of my data area,
  100.          *                              spins until they are different)
  101.          * After:
  102.          *   %ah = laddr [last] [16]   (orig contents of private data area of
  103.          *                              last process to request lock)
  104.          *   %al = last_p_pid * 2      (used to find CURRENT contents of last
  105.          *                              lock requestor's private data)
  106.      */
  107.     xchgl    %eax,0(laddr)
  108.  
  109.     /*
  110.          * Move last lock requestor's process_id*2 into low bits of %edx.
  111.          * The 'cmpb' below will use this value in a complex addressing mode
  112.          * as was done above.
  113.      */
  114.     movb    %al,%dl
  115.  
  116.     /* 
  117.          * Now spin until last lock requestor is done with the lock and
  118.          * updates his private data location.  I.e., spin until original
  119.          * contents of his location (%ah) and current contents
  120.          * (laddr [last_pid] [16]) become different.  Since we are the only
  121.          * one spinning on this location, the location is in it's 'own'
  122.          * cache line, and there will be exactly one write to the location,
  123.          * cache coherency traffic is minimized.
  124.      */
  125. spin:    cmpb    %ah,16(laddr,%edx,8)
  126.     je    spin                     /* values still equal - spin */
  127.  
  128.     /*
  129.          * Values are no longer equal - so previous lock requestor must be
  130.          * done with the lock.
  131.          *
  132.          * We now own it - proceed!
  133.      */
  134. done:
  135. /PEEPON
  136. %mem laddr; lab spin, done;
  137. /PEEPOFF
  138.     /* SEE COMMENTS ABOVE */
  139.     movl    laddr,%ecx
  140.     movl    _thisproc, %edx
  141.     movl    THISPROC_ID_OFFSET(%edx), %edx
  142.     incl    %edx
  143.     addl    %edx,%edx
  144.     movl    %edx,%eax
  145.     movb    16(%ecx,%edx,8),%ah
  146.     xchgl    %eax,0(%ecx)
  147.     movb    %al,%dl
  148. spin:    cmpb    %ah,16(%ecx,%edx,8)
  149.     je    spin
  150. done:
  151. /PEEPON
  152. }
  153.  
  154. /*
  155.  *  HC_S_UNLOCK - release high contention spinlock.
  156.  */
  157. asm void HC_S_UNLOCK(laddr)
  158. {
  159. %reg laddr;
  160.     /* 
  161.          * Get processor id and convert into 1 to NUMPROCS format
  162.          * (from 0 to NUMPROCS-1).
  163.      */
  164.     movl    _thisproc, %edx
  165.     movl    THISPROC_ID_OFFSET(%edx), %edx
  166.     incl    %edx
  167.  
  168.     /*
  169.          * Find this processor's row in the lock data array (%edx = 16*p_pid).
  170.      */
  171.     shll    $4,%edx
  172.  
  173.     /*
  174.          * Increment this processor's private data location.  This allows
  175.          * anyone spinning on that location to proceed.  If no one was
  176.          * spinning (i.e., this processor was the last processor to request
  177.          * the lock), then the private data location will contain a different
  178.          * value then the original value stored in laddr [0][0], so later
  179.          * when someone does request the lock, they'll get it immediately.
  180.      */
  181.     incb    16(laddr,%edx)
  182.  
  183. %mem laddr;
  184.     /* SEE COMMENTS ABOVE */
  185.     movl    laddr, %ecx
  186.     movl    _thisproc, %edx
  187.     movl    THISPROC_ID_OFFSET(%edx), %edx
  188.     incl    %edx
  189.     shll    $4,%edx
  190.     incb    16(%ecx,%edx)
  191. }
  192.  
  193. asm HC_S_INIT_LOCK(laddr)
  194. {
  195. %reg laddr;
  196.     /* 
  197.          * The first row of the lock data array is used to store the id
  198.          * of the last processor to request the lock, as well as the contents
  199.          * of the requesting processor's private data area.
  200.          *
  201.          * Start out with 'dummy' processor 0 and a dummy data value of 0.
  202.          */
  203.     movl    $0,(laddr)
  204.  
  205.     /*
  206.          * Now set laddr [0][16] to 1.  This is 'dummy' processor 0's
  207.          * private data location.  Since this value is different than the
  208.          * original value of 0 loaded above, the first processor to request
  209.          * the lock in HC_S_LOCK will get it immediately, without spinning.
  210.      */
  211.     movb    $1,16(laddr)
  212. %mem laddr;
  213.     /* SEE COMMENTS ABOVE */
  214.     movl    laddr, %ecx
  215.     movl    $0,(%ecx)
  216.     movb    $1,16(%ecx)
  217. }
  218.  
  219. asm int HC_S_IS_LOCKED(laddr)
  220. {
  221. %reg laddr;
  222. /PEEPOFF
  223.         /*
  224.          *  Get proc_id*2 of last thread to request the lock (%al), and
  225.          *  value of that processor's private data location when lock
  226.          *  was requested (%ah).
  227.          */
  228.     movl    0(laddr),%eax     
  229.  
  230.     /* 
  231.          *  Load last_pid*2 into low bits of %edx.
  232.      */
  233.     subl    %edx,%edx          /* %edx = 0 */
  234.     movb    %al,%dl
  235.  
  236.     /*
  237.          * Use complex addressing mode (described in HC_S_LOCK) to see if
  238.          * last lock requestor's private data has changed since he requested
  239.          * the lock.  If not, then either he still has the lock, or he is
  240.          * still in the queue waiting to get the lock, and the lock is HELD.
  241.          * Otherwise, the two values are different, and the lock must be FREE.
  242.          *
  243.          *   %ah - original value of last lock requestor's private data
  244.          *   16(laddr,%edx,8) - as described in HC_S_LOCK, this is
  245.          *                      laddr [last_pid] [16], which stores the
  246.          *                      CURRENT value of last lock requestor's
  247.          *                      private data area.
  248.      */
  249.     cmpb    %ah,16(laddr,%edx,8)
  250.  
  251.     /*
  252.          *  Return indication of whether lock is held or free.
  253.          *  If equal, set %al and mask the rest of %eax to 0.
  254.          */
  255.     sete    %al
  256.     andl    $0xff,%eax
  257. /PEEPON
  258. %mem laddr;
  259. /PEEPOFF
  260.     /* SEE COMMENTS ABOVE */
  261.     movl    laddr,%ecx
  262.     movl    0(%ecx),%eax
  263.     subl    %edx,%edx
  264.     movb    %al,%dl
  265.     cmpb    %ah,16(%ecx,%edx,8)
  266.     sete    %al
  267.     andl    $0xff,%eax
  268. /PEEPON
  269. }
  270.  
  271.  
  272. /* XXX UNIMPLEMENTED -- should never be called */
  273. /* always return FALSE */
  274. asm int HC_S_CLOCK(laddr)
  275. {
  276. %reg laddr;
  277.     movl    $L_FAILED, %eax
  278. %mem laddr; lab spin, failed, done;
  279.     movl    $L_FAILED, %eax
  280. done:
  281. /PEEPON
  282. }
  283.  
  284. #endif /* __presto__hc_slock_asm_h__ */
  285.